import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

public class FileManager {
  private static final String FILENAME = "tasks.csv"; // Haven decide on Filename
  private final String NOTHING = "";
  private final String MESSAGE_ERROR_CREATE_CSV_FILE = "createCSVFile funtion error!";
  private boolean isCsvUpdated = true;
  private int undoCounter = 0;
  private int addCounter = 0;
  private ArrayList<Task> listOfTasks;
  private ArrayList<Task> initialListOfTasks;
  private Stack<ArrayList<Task>> stackRepo;
  
  private AttributeHandler attributeHandler;
  private CsvReader csvReader;
  private CsvWriter csvWriter;

  public FileManager() {
	listOfTasks = new ArrayList<Task>();
	initialListOfTasks = new ArrayList<Task>();
	stackRepo = new Stack<ArrayList<Task>>();
	attributeHandler = new AttributeHandler();
	csvReader = new CsvReader();
	csvWriter = new CsvWriter();
    createCSVFileIfCSVFileNotExisted();
    initialListOfTasks = readListOfTaskObjects();
    listOfTasks = readListOfTaskObjects();
    isCsvUpdated = false;
  }

  private void createCSVFileIfCSVFileNotExisted() {
    try {
      checkIfCSVFileExisted();
    } catch (IOException FileNotFound) {
      createCSVFile();
    }
  }

  private void checkIfCSVFileExisted() throws FileNotFoundException, IOException {
    FileReader fileReader = new FileReader(FILENAME);
    BufferedReader bufferedReader = new BufferedReader(fileReader);

    bufferedReader.close();
  }

  private void createCSVFile() {
    try {
      FileWriter fileWriter = new FileWriter(FILENAME);
      PrintWriter printWriter = new PrintWriter(fileWriter);

      printWriter.print(NOTHING);
      printWriter.close();
      
      //stackRepo.push(null);
      isCsvUpdated = true;
    } catch (IOException e) {
      System.out.println(MESSAGE_ERROR_CREATE_CSV_FILE);
    }
  }

  public ArrayList<Task> processCommands(String inputCommand, String userInput, Task dataBuffer, ArrayList<Task> dataBufferList) {
	if(inputCommand.toUpperCase().equals("UNDO")) {
		undoCounter++;
	} else {
		undoCounter = 0;
	}
	
    switch (inputCommand.toUpperCase()) {
    	case "ADD" :
    		addCounter++;
    		addCommand(dataBuffer);
    		listOfTasks = readListOfTaskObjects();
    		stackRepo.push(listOfTasks);
    		break;

    	case "READ" :
    		readListOfTaskObjects();
    		break;

    	case "REMOVE" :
    		listOfTasks = dataBufferList;    
    		removeCommand(listOfTasks);
    		stackRepo.push(listOfTasks);
    		break;

    	case "CLEAR" :
    		//add create csv file to stack before delete; for "undo" purposes
    		//implement in the later part
    		csvWriter.clear();
    		listOfTasks = null;
    		stackRepo.push(listOfTasks);
    		isCsvUpdated = true;
    		break;
    	
    	case "SORT" :
    		listOfTasks = readListOfTaskObjects();
    		listOfTasks = sortTasksInCSV(userInput, listOfTasks);    		
    		csvWriter.write(null, attributeHandler.convertTaskToString(listOfTasks));
    		stackRepo.push(listOfTasks);
    		isCsvUpdated = true; 
    		break;
    	
    	case "MODIFY" :
    		listOfTasks = dataBufferList;    		
    		csvWriter.write(listOfTasks);
    		stackRepo.push(listOfTasks);
    		isCsvUpdated = true;
    		break;
    	
    	case "UNDO" :
    		if(stackRepo.isEmpty()) {
    			System.out.println("Nothing to undo!");
    		} else {    			
    			if(undoCounter > 1) { //user keep undo-ing
    				listOfTasks = stackRepo.pop();    			
    				csvWriter.write(listOfTasks);
    				isCsvUpdated = true;
    			} else {
    				if (stackRepo.size() == 1 && addCounter == 1){ //only one item added    					
        				stackRepo.pop();
        				csvWriter.write(initialListOfTasks);
        				isCsvUpdated = true;
        			} else {
        				stackRepo.pop();
        				listOfTasks = stackRepo.pop();    			
        				csvWriter.write(listOfTasks);
        				isCsvUpdated = true;
        			}
    			}
    		}    		
    		break;
    	
    	default :
    }
    
    //stackRepo.push(listOfTasks);
    return listOfTasks;
  }
  
  private ArrayList<Task> readListOfTaskObjects() {
	  String output = (isCsvUpdated) ? "True" : "False"; //testing
	  System.out.println(output);
	  if (isCsvUpdated) {
		  listOfTasks = csvReader.read();
		  isCsvUpdated = false;
	  }
	  return listOfTasks;
  }
  
  private ArrayList<Task> sortTasksInCSV(String inputCommand, ArrayList<Task> listOfTasks) {
	  switch(inputCommand.toUpperCase()) {
	  	case "TITLE" :
	  		Collections.sort(listOfTasks, Task.TaskTitleComparator);
	  		break;
	  		
	  	case "DATE" :
	  		Collections.sort(listOfTasks, Task.TaskDateComparator);
	  		break;
	  		
	  	case "URGENCYLEVEL" :
	  		Collections.sort(listOfTasks, Task.TaskUrgencyLevelComparator);
	  		break;
	  		
	  	default :
	  		
	  		break;
	  }
	  return listOfTasks;
  }

  private void addCommand(Task dataBuffer) {
    String csvEntryString = attributeHandler.convertTaskToString(dataBuffer);
    csvWriter.write(csvEntryString, null);
    isCsvUpdated = true;
  }

  
private void removeCommand(ArrayList<Task> dataBufferList) {
    csvWriter.write(dataBufferList);
    isCsvUpdated = true;
  }
  
  public static String getFileName() {
	  return FILENAME;
  }
}

